package ai.xiaodao.trade;

import ai.xiaodao.config.BrokerConfig;
import ai.xiaodao.config.Security;
import ai.xiaodao.db.OrderOps;
import com.futu.openapi.FTAPI_Conn;
import com.futu.openapi.FTAPI_Conn_Qot;
import com.futu.openapi.FTSPI_Conn;
import com.futu.openapi.FTSPI_Qot;
import com.futu.openapi.pb.*;
import org.apache.log4j.Logger;

import javax.security.auth.callback.Callback;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Paths;

/**
 * 行情服务
 */

//行情示例
public class SecQuote implements FTSPI_Qot, FTSPI_Conn, Callback {
    FTAPI_Conn_Qot qot = new FTAPI_Conn_Qot();
    private SecTrade trade;
    static Logger log = Logger.getLogger(SecQuote.class.getName());

    public SecQuote(SecTrade trade) {
        qot.setClientInfo("javaclient", 1);  //设置客户端信息
        qot.setConnSpi(this);  //设置连接回调
        qot.setQotSpi(this);   //设置行情回调
        this.trade = trade;
    }

    //连接OpenD
    public void start(boolean isEnableEncrypt) {
        if (isEnableEncrypt) {
            String rsaKey = null;
            try {
                byte[] buf = java.nio.file.Files.readAllBytes(Paths.get("c:\\rsa1024"));
                rsaKey = new String(buf, Charset.forName("UTF-8"));
                qot.setRSAPrivateKey(rsaKey);
            } catch (IOException e) {

            }
        }

        qot.initConnect(BrokerConfig.getOpendIP(), BrokerConfig.getOpendPort(), isEnableEncrypt);
    }

    //获取全局状态
    public void getGlobalState() {
        GetGlobalState.Request req = GetGlobalState.Request.newBuilder().setC2S(
                GetGlobalState.C2S.newBuilder().setUserID(BrokerConfig.getUserID())
        ).build();
        int seqNo = qot.getGlobalState(req);
        log.info("Send GetGlobalState: " + seqNo);
    }

    //测试订阅行情
    void sub() {
        QotCommon.Security sec = QotCommon.Security.newBuilder().setCode(Security.getCode())
                .setMarket(Security.getMarket())
                .build();
        QotSub.C2S c2s = QotSub.C2S.newBuilder().addSecurityList(sec)
                .addSubTypeList(QotCommon.SubType.SubType_Basic_VALUE)
                .setIsSubOrUnSub(true)
                .setIsRegOrUnRegPush(true)
                .setIsFirstPush(true)
                .build();
        QotSub.Request req = QotSub.Request.newBuilder().setC2S(c2s).build();
        qot.sub(req);
    }

    //测试获取订阅状态
    void getSubInfo() {
        QotGetSubInfo.C2S c2s = QotGetSubInfo.C2S.newBuilder().build();
        QotGetSubInfo.Request req = QotGetSubInfo.Request.newBuilder().setC2S(c2s).build();
        qot.getSubInfo(req);
    }

    //测试获取基本行情，需要先订阅才能获取
    void getBasicQot() {
        QotCommon.Security sec1 = QotCommon.Security.newBuilder().setCode("00388")
                .setMarket(QotCommon.QotMarket.QotMarket_HK_Security.getNumber())
                .build();
        QotGetBasicQot.C2S c2s = QotGetBasicQot.C2S.newBuilder().addSecurityList(sec1).build();
        QotGetBasicQot.Request req = QotGetBasicQot.Request.newBuilder().setC2S(c2s).build();
        qot.getBasicQot(req);
    }


    //与OpenD连接和初始化完成，可以进行各种业务请求。如果ret为false，表示失败，desc中有错误信息
    @Override
    public void onInitConnect(FTAPI_Conn client, long errCode, String desc) {
        System.out.printf("Qot onInitConnect: ret=%b desc=%s connID=%d\n", errCode, desc, client.getConnectID());
        if (errCode != 0)
            return;

//        InitConnect成功返回才能继续后面的请求
        this.getGlobalState();
        this.sub();
        this.getSubInfo();
    }

    @Override
    public void onDisconnect(FTAPI_Conn client, long errCode) {
        System.out.printf("Qot onDisConnect: %d\n", errCode);
    }

    @Override
    public void onReply_GetGlobalState(FTAPI_Conn client, int nSerialNo, GetGlobalState.Response rsp) {
        log.info("Received: GetGlobalState: " + nSerialNo);
    }

    @Override
    public void onReply_Sub(FTAPI_Conn client, int nSerialNo, QotSub.Response rsp) {
        log.info("Reply: Sub: " + nSerialNo);
    }

    @Override
    public void onReply_GetSubInfo(FTAPI_Conn client, int nSerialNo, QotGetSubInfo.Response rsp) {
        log.debug("Reply: getSubInfo: " + rsp.getRetMsg()+rsp.toString());
    }

    @Override
    public void onReply_RequestTradeDate(FTAPI_Conn client, int nSerialNo, QotRequestTradeDate.Response rsp) {
        System.out.printf("onReply_RequestTradeDate: %d %s\n", nSerialNo, rsp.toString());
    }

    @Override
    public  void onReply_GetBasicQot(FTAPI_Conn client, int nSerialNo, QotGetBasicQot.Response rsp) {
        System.out.printf("Reply: QotGetBasicQot: %d  %s\n", nSerialNo, rsp.toString());
    }

    @Override
    public void onPush_UpdateBasicQuote(FTAPI_Conn client, QotUpdateBasicQot.Response rsp) {
//        System.out.printf("onPush_UpdateBasicQuote: %s\n", rsp.toString());
//        QotCommon.BasicQot quote = QotGetBasicQot
        QotCommon.BasicQot qot = rsp.getS2C().getBasicQotList(0);
        String date = qot.getUpdateTime();
        String code = qot.getSecurity().getCode();
        double curPrice = qot.getCurPrice();
        int trdSide = TradeOps.getTradeSide(curPrice);
        Double price = TradeOps.getTrdPrice(trdSide);
        int trdQty = Security.getTrdQty();
        int market = Security.getMarket();
        int trdEnv = BrokerConfig.getTrdEnv();

        LocalOrder localOrder = new LocalOrder(code, market, trdSide, trdQty, price);

        /*
        如果股票价格达到设置的的买入价格，则检查本地是否有买未且未卖出的订单记录，如果没有则进行买入操作
         */
        if (trdSide == TrdCommon.TrdSide.TrdSide_Buy_VALUE) {
            log.debug(" code: " + code + " current price : " + curPrice + " the security price touched the buy trigger price: " + Security.getBuyTriggerPrice());
            if (!OrderOps.hasRecord(localOrder)) {
                //submit the order
                int rs = trade.placeOrder(localOrder, trdEnv);
                if (rs != 0) {
                    //add local submit record
                    OrderOps.addLocalSubmitRecord(localOrder);
                    log.info("order submitted");
                } else {
                    log.error("the connection id  is  " + rs +".please check your connection");
                }
                //添加本地买单提交记录

                log.info("order submitted");
            } else {
//                trade.getOrderList();
                log.info("The last buy order did not sale");
            }
        }

        /*
         *如果股票价格到达卖出的触发价，
         * 1 查看本地是否有未完成的记录
         * 2 查看上一笔订单是否为买入
         * 3 如果上一笔订单为习入且价格、代码、数量 数量与本地记录一致，则进行卖出操作
         */

        if (trdSide == TrdCommon.TrdSide.TrdSide_Sell_VALUE) {
            log.info(" code :" + code + " current price : "
                    + curPrice + " the security price reached the sale trigger price: "
                    + Security.getSaleTriggerPrice());
            if (OrderOps.hasBuyRecord(localOrder) && (!OrderOps.hasSellRecord(localOrder))) {
                //添加本地卖单记录
                OrderOps.addLocalSubmitRecord(localOrder);
                log.debug("start to sale the sec ");
                trade.placeOrder(localOrder, trdEnv);

            } else {
                log.info("no sec to sale ");
            }
        }
        log.info("do nothing the price not in "+Security.getBuyTriggerPrice()+ " to " +Security.getSaleTriggerPrice());
    }


}

